package core.java;

import java.lang.reflect.*;
import java.util.Arrays;


import static java.lang.System.*;

/**
 *
 */
public class ReflectionStudy   {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, IllegalAccessException, NoSuchFieldException {
         //init("java.lang.Integer")
           init("java.util.LinkedList");
           init("core.java.ReflectionStudy");
          out.println(java.lang.Integer.class.getMethod("sum", int.class, int.class).invoke(null, new Object[] {1, 1}));
          out.println(java.lang.Integer.class.getField("MAX_VALUE").getInt(null));

    }
    public static void init(String className) throws ClassNotFoundException {
        init(className,true);
    }
    public static void init(String className ,boolean isSimpleName) throws ClassNotFoundException {
        Class cla = Class.forName(className);
        printClassName(cla,isSimpleName);
        printClassGenericity(cla,isSimpleName);
        printClassExtends(cla,isSimpleName);
        printClassInterface(cla,isSimpleName);
        out.println(" {");
        printField(cla,isSimpleName);
        printConstructor(cla,isSimpleName);
        printMethods(cla,isSimpleName);
        out.println("}");
    }
    public static void printClassName(Class<?> cla ,boolean isSimpleName) {
        if (isSimpleName)
            out.print(Modifier.toString(cla.getModifiers()) + " " + cla.getSimpleName());
        else
            out.print(Modifier.toString(cla.getModifiers()) + " " + cla.getName());
    }
    public static void printClassGenericity(Class<?> cla,boolean isSimpleName) {
        TypeVariable typeVariable[] = cla.getTypeParameters();
        printTypes(typeVariable,"<",",",">",true,isSimpleName);
    }
    public static void printClassExtends(Class<?> cla,boolean isSimpleName) {
        Type sup = cla.getGenericSuperclass();
            if (sup.equals(Object.class)) return;
            out.print(" extends ");
            printType(sup,true,isSimpleName);

    }
    public static void printClassInterface(Class<?> cla,boolean isSimpleName) {
        Type inter[] = cla.getGenericInterfaces();
        printTypes(inter," implements ",",","",true,isSimpleName);

    }

    /**
     * @param types 类型
     * @param pre 输出前缀
     * @param sep  分隔
     * @param suf 后缀
     * @param isDefintion 是否再分
     * 输出类型
     */
    public static void printTypes(Type[] types,String pre,String sep,String suf,boolean isDefintion,boolean isSimpleName) {
        if (types.length <=0||pre.equals(" extends ")&& Arrays.equals(types,new Type[]{Object.class})) {
            if (pre.trim().equals("(")) out.print(pre+suf);
            return;
        }
        out.print(pre);
        for (int i = 0; i < types.length; i++) {
            if (i!=0) out.print(sep);
            printType(types[i],isDefintion,isSimpleName);
        }
        out.print(suf);

    }

    /**
     *
     * @param type 类型
     * @param isDefintion 是否再分
     *
     * Class 类
     * TypeVariable 描述泛型  T extends Comparable<? super T>
     * WildcardType  描述泛型   <? extends A> <? super A>
     * parameterizedType 描述泛型 描述泛型类和接口 Comparable<? super T>
     * GenericArrayType 描述泛型 泛型数组 T[]
     */
    public static void printType(Type type, boolean isDefintion,boolean isSimpleName) {
        if (type instanceof Class) {
            Class<?> cla = (Class<?>)type;
            if (!isSimpleName)
               out.print(cla.getName());
            else out.print(cla.getSimpleName());
        } else if (type instanceof TypeVariable) {
            TypeVariable<?> typeVariable = (TypeVariable<?>)type;
            if (!isSimpleName)
                out.print(typeVariable.getName());
            else
                out.print(typeVariable.getTypeName());
            if (isDefintion) {
                printTypes(typeVariable.getBounds()," extends "," & ","",false,isSimpleName);
            }
        } else if (type instanceof WildcardType) {
            WildcardType wildcardType = (WildcardType)type;
            out.print("?");
            printTypes(wildcardType.getLowerBounds()," extends "," & ","",false,isSimpleName);
            printTypes(wildcardType.getUpperBounds()," super "," & ","",false,isSimpleName);
        } else if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType)type;
            Type owner = parameterizedType.getOwnerType();
            if (owner!=null) {
                printType(owner,false,isSimpleName);
                out.print(".");
            }
            printType(parameterizedType.getRawType(),false,isSimpleName);
            printTypes(parameterizedType.getActualTypeArguments(),"<",",",">",false,isSimpleName);
        } else if (type instanceof GenericArrayType) {
            GenericArrayType genericArrayType = (GenericArrayType)type;
            printType(genericArrayType.getGenericComponentType(),isDefintion,isSimpleName);
            out.print("[]");
        }
    }
    public static void printField(Class cla,boolean isSimpleName) {
        Field[] fields = cla.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getName();
            String modifierName = Modifier.toString(fields[i].getModifiers());
            Type type = fields[i].getType();
            out.print(' ');
            if (modifierName.length() > 0) {
                out.print(modifierName + ' ');
            }
            printType(type,true,isSimpleName);
            out.print(name);
            out.println(";");
        }

    }
    public static void printConstructor(Class cla,boolean isSimpleName) {
        Constructor[] constructors = cla.getDeclaredConstructors();
        for (Constructor c:constructors) {
            String modifierName = Modifier.toString(c.getModifiers());
            out.print(' ');
            if (modifierName.length() > 0) {
                out.print(modifierName + ' ');
            }
            out.print(c.getName());
            Type[] constructorsParmTypes = c.getGenericParameterTypes();
            Type[] exceptions = c.getGenericExceptionTypes();
            if (exceptions.length>0)
                printTypes(constructorsParmTypes," (",",",")",true,isSimpleName);
            else
                printTypes(constructorsParmTypes," (",",",") {...}",true,isSimpleName);
            printTypes(exceptions," throws",",","{...}",true,isSimpleName);
            out.println();
        }
    }
    public static void printMethods(Class<?> cla,boolean isSimpleName) {
        Method[] methods = cla.getMethods();
        for (Method method:methods) {
            out.print(' ');
            String modifieName = Modifier.toString(method.getModifiers());
            if (modifieName.length() > 0) {
                out.print(modifieName + ' ');
            }

            Type returnType = method.getGenericReturnType();
            printType(returnType,true,isSimpleName);
            out.print(" "+method.getName()+" ");
            Type[] methodsParmarType = method.getGenericParameterTypes();
            Type[] exceptions = method.getGenericExceptionTypes();
            if (exceptions.length>0)
                printTypes(methodsParmarType,"(",",",") ",true,isSimpleName);
            else
                printTypes(methodsParmarType,"(",",","){...}",true,isSimpleName);
            printTypes(exceptions," throws ",",","{...}",true,isSimpleName);
            out.println();

        }


    }

}
